1 # INAV Programming Framework
3 INAV Programming Framework (abbr. IPF) is a mechanism that allows to evaluate cenrtain flight parameters (RC channels, switches, altitude, distance, timers, other logic conditions) and use the value of evaluated expression in different places of INAV. Currently, the result of LCs can be used in:
5 * [Servo mixer](Mixer.md) to activate/deactivate certain servo mix rulers
6 * To activate/deactivate system overrides
8 INAV Programming Framework coinsists of:
10 * Logic Conditions - each Logic Condition can be understood as a single command, a single line of code
11 * Global Variables - variables that can store values from and for LogiC Conditions and servo mixer
12 * Programming PID - general purpose, user configurable PID controllers
14 IPF can be edited using INAV Configurator user interface, or via CLI
20 `logic <rule> <enabled> <activatorId> <operation> <operand A type> <operand A value> <operand B type> <operand B value> <flags>`
22 * `<rule>` - ID of Logic Condition rule
23 * `<enabled>` - `0` evaluates as disabled, `1` evaluates as enabled
24 * `<activatorId>` - the ID of _LogicCondition_ used to activate this _Condition_. _Logic Condition_ will be evaluated only then Activator evaluates as `true`. `-1` evaluates as `true`
25 * `<operation>` - See `Operations` paragraph
26 * `<operand A type>` - See `Operands` paragraph
27 * `<operand A value>` - See `Operands` paragraph
28 * `<operand B type>` - See `Operands` paragraph
29 * `<operand B value>` - See `Operands` paragraph
30 * `<flags>` - See `Flags` paragraph
34 | Operation ID | Name | Notes |
35 |---------------|-------------------------------|-------|
36 | 0 | TRUE | Always evaluates as true |
37 | 1 | EQUAL | Evaluates `false` if `false` or `0` |
38 | 2 | GREATER_THAN | `true` if `Operand A` is a higher value than `Operand B` |
39 | 3 | LOWER_THAN | `true` if `Operand A` is a lower value than `Operand B` |
40 | 4 | LOW | `true` if `<1333` |
41 | 5 | MID | `true` if `>=1333 and <=1666` |
42 | 6 | HIGH | `true` if `>1666` |
43 | 7 | AND | `true` if `Operand A` and `Operand B` are the same value or both `true` |
44 | 8 | OR | `true` if `Operand A` and/or `OperandB` is `true` |
45 | 9 | XOR | `true` if `Operand A` or `Operand B` is `true`, but not both |
46 | 10 | NAND | `false` if `Operand A` and `Operand B` are both `true`|
47 | 11 | NOR | `true` if `Operand A` and `Operand B` are both `false` |
48 | 12 | NOT | The boolean opposite to `Operand A` |
49 | 13 | STICKY | `Operand A` is the activation operator, `Operand B` is the deactivation operator. After the activation is `true`, the operator will return `true` until Operand B is evaluated as `true`|
50 | 14 | ADD | Add `Operand A` to `Operand B` and returns the result |
51 | 15 | SUB | Substract `Operand B` from `Operand A` and returns the result |
52 | 16 | MUL | Multiply `Operand A` by `Operand B` and returns the result |
53 | 17 | DIV | Divide `Operand A` by `Operand B` and returns the result |
54 | 18 | GVAR SET | Store value from `Operand B` into the Global Variable addressed by `Operand B`. Bear in mind, that operand `Global Variable` means: Value stored in Global Variable of an index! To store in GVAR 1 use `Value 1` not `Global Variable 1` |
55 | 19 | GVAR INC | Increase the GVAR indexed by `Operand A` (use `Value 1` for Global Variable 1) with value from `Operand B` |
56 | 20 | GVAR DEC | Decrease the GVAR indexed by `Operand A` (use `Value 1` for Global Variable 1) with value from `Operand B` |
57 | 21 | IO PORT SET | Set I2C IO Expander pin `Operand A` to value of `Operand B`. `Operand A` accepts values `0-7` and `Operand B` accepts `0` and `1` |
58 | 22 | OVERRIDE_ARMING_SAFETY | Allows the craft to arm on any angle even without GPS fix. WARNING: This bypasses all safety checks, even that the throttle is low, so use with caution. If you only want to check for certain conditions, such as arm without GPS fix. You will need to add logic conditions to check the throttle is low. |
59 | 23 | OVERRIDE_THROTTLE_SCALE | Override throttle scale to the value defined by operand. Operand type `0` and value `50` means throttle will be scaled by 50%. |
60 | 24 | SWAP_ROLL_YAW | basically, when activated, yaw stick will control roll and roll stick will control yaw. Required for tail-sitters VTOL during vertical-horizonral transition when body frame changes |
61 | 25 | SET_VTX_POWER_LEVEL | Sets VTX power level. Accepted values are `0-3` for SmartAudio and `0-4` for Tramp protocol |
62 | 26 | INVERT_ROLL | Inverts ROLL axis input for PID/PIFF controller |
63 | 27 | INVERT_PITCH | Inverts PITCH axis input for PID/PIFF controller |
64 | 28 | INVERT_YAW | Inverts YAW axis input for PID/PIFF controller |
65 | 29 | OVERRIDE_THROTTLE | Override throttle value that is fed to the motors by mixer. Operand is scaled in us. `1000` means throttle cut, `1500` means half throttle |
66 | 30 | SET_VTX_BAND | Sets VTX band. Accepted values are `1-5` |
67 | 31 | SET_VTX_CHANNEL | Sets VTX channel. Accepted values are `1-8` |
68 | 32 | SET_OSD_LAYOUT | Sets OSD layout. Accepted values are `0-3` |
69 | 33 | SIN | Computes SIN of `Operand A` value in degrees. Output is multiplied by `Operand B` value. If `Operand B` is `0`, result is multiplied by `500` |
70 | 34 | COS | Computes COS of `Operand A` value in degrees. Output is multiplied by `Operand B` value. If `Operand B` is `0`, result is multiplied by `500` |
71 | 35 | TAN | Computes TAN of `Operand A` value in degrees. Output is multiplied by `Operand B` value. If `Operand B` is `0`, result is multiplied by `500` |
72 | 36 | MAP_INPUT | Scales `Operand A` from [`0` : `Operand B`] to [`0` : `1000`]. Note: input will be constrained and then scaled |
73 | 37 | MAP_OUTPUT | Scales `Operand A` from [`0` : `1000`] to [`0` : `Operand B`]. Note: input will be constrained and then scaled |
74 | 38 | RC_CHANNEL_OVERRIDE | Overrides channel set by `Operand A` to value of `Operand B` |
75 | 39 | SET_HEADING_TARGET | Sets heading-hold target to `Operand A`, in degrees. Value wraps-around. |
76 | 40 | MOD | Modulo. Divide `Operand A` by `Operand B` and returns the remainder |
77 | 41 | LOITER_RADIUS_OVERRIDE | Sets the loiter radius to `Operand A` [`0` : `100000`] in cm. If the value is lower than the loiter radius set in the **Advanced Tuning**, that will be used. |
78 | 42 | SET_PROFILE | Sets the active config profile (PIDFF/Rates/Filters/etc) to `Operand A`. `Operand A` must be a valid profile number, currently from 1 to 3. If not, the profile will not change |
79 | 43 | MIN | Finds the lowest value of `Operand A` and `Operand B` |
80 | 44 | MAX | Finds the highest value of `Operand A` and `Operand B` |
81 | 45 | FLIGHT_AXIS_ANGLE_OVERRIDE | Sets the target attitude angle for axis. In other words, when active, it enforces Angle mode (Heading Hold for Yaw) on this axis (Angle mode does not have to be active). `Operand A` defines the axis: `0` - Roll, `1` - Pitch, `2` - Yaw. `Operand B` defines the angle in degrees |
82 | 46 | FLIGHT_AXIS_RATE_OVERRIDE | Sets the target rate (rotation speed) for axis. `Operand A` defines the axis: `0` - Roll, `1` - Pitch, `2` - Yaw. `Operand B` defines the rate in degrees per second |
83 | 47 | EDGE | Momentarily true when triggered by `Operand A`. `Operand A` is the activation operator [`boolean`], `Operand B` _(Optional)_ is the time for the edge to stay active [ms]. After activation, operator will return `true` until the time in Operand B is reached. If a pure momentary edge is wanted. Just leave `Operand B` as the default `Value: 0` setting. |
84 | 48 | DELAY | Delays activation after being triggered. This will return `true` when `Operand A` _is_ true, and the delay time in `Operand B` [ms] has been exceeded. |
85 | 49 | TIMER | A simple on - off timer. `true` for the duration of `Operand A` [ms]. Then `false` for the duration of `Operand B` [ms]. |
86 | 50 | DELTA | This returns `true` when the value of `Operand A` has changed by the value of `Operand B` or greater within 100ms. |
87 | 51 | APPROX_EQUAL | `true` if `Operand B` is within 1% of `Operand A`. |
91 | Operand Type | Name | Notes |
92 |---------------|-----------------------|-------|
93 | 0 | VALUE | Value derived from `value` field |
94 | 1 | GET_RC_CHANNEL | `value` points to RC channel number, indexed from 1 |
95 | 2 | FLIGHT | `value` points to flight parameter table |
96 | 3 | FLIGHT_MODE | `value` points to flight modes table |
97 | 4 | LC | `value` points to other logic condition ID |
98 | 5 | GVAR | Value stored in Global Variable indexed by `value`. `GVAR 1` means: value in GVAR 1 |
99 | 5 | PID | Output of a Programming PID indexed by `value`. `PID 1` means: value in PID 1 |
103 | Operand Value | Name | Notes |
104 |---------------|-------------------------------|-------|
105 | 0 | ARM_TIMER | in `seconds` |
106 | 1 | HOME_DISTANCE | in `meters` |
107 | 2 | TRIP_DISTANCE | in `meters` |
109 | 4 | VBAT | in `Volts * 100`, eg. `12.1V` is `1210` |
110 | 5 | CELL_VOLTAGE | in `Volts * 100`, eg. `12.1V` is `1210` |
111 | 6 | CURRENT | in `Amps * 100`, eg. `9A` is `900` |
112 | 7 | MAH_DRAWN | in `mAh` |
114 | 9 | GROUD_SPEED | in `cm/s` |
115 | 10 | 3D_SPEED | in `cm/s` |
116 | 11 | AIR_SPEED | in `cm/s` |
117 | 12 | ALTITUDE | in `cm` |
118 | 13 | VERTICAL_SPEED | in `cm/s` |
119 | 14 | TROTTLE_POS | in `%` |
120 | 15 | ATTITUDE_ROLL | in `degrees` |
121 | 16 | ATTITUDE_PITCH | in `degrees` |
122 | 17 | IS_ARMED | boolean `0`/`1` |
123 | 18 | IS_AUTOLAUNCH | boolean `0`/`1` |
124 | 19 | IS_ALTITUDE_CONTROL | boolean `0`/`1` |
125 | 20 | IS_POSITION_CONTROL | boolean `0`/`1` |
126 | 21 | IS_EMERGENCY_LANDING | boolean `0`/`1` |
127 | 22 | IS_RTH | boolean `0`/`1` |
128 | 23 | IS_LANDING | boolean `0`/`1` |
129 | 24 | IS_FAILSAFE | boolean `0`/`1` |
130 | 25 | STABILIZED_ROLL | Roll PID controller output `[-500:500]` |
131 | 26 | STABILIZED_PITCH | Pitch PID controller output `[-500:500]` |
132 | 27 | STABILIZED_YAW | Yaw PID controller output `[-500:500]` |
133 | 28 | 3D HOME_DISTANCE | in `meters`, calculated from HOME_DISTANCE and ALTITUDE using Pythagorean theorem |
134 | 29 | CROSSFIRE LQ | Crossfire Link quality as returned by the CRSF protocol |
135 | 30 | CROSSFIRE SNR | Crossfire SNR as returned by the CRSF protocol |
136 | 31 | GPS_VALID | boolean `0`/`1`. True when the GPS has a valid 3D Fix |
137 | 32 | LOITER_RADIUS | The current loiter radius in cm. |
138 | 33 | ACTIVE_PROFILE | integer for the active config profile `[1..MAX_PROFILE_COUNT]` |
139 | 34 | BATT_CELLS | Number of battery cells detected |
140 | 35 | AGL_STATUS | boolean `1` when AGL can be trusted, `0` when AGL estimate can not be trusted |
141 | 36 | AGL | integer Above The Groud Altitude in `cm` |
142 | 37 | RANGEFINDER_RAW | integer raw distance provided by the rangefinder in `cm` |
146 The flight mode operands return `true` when the mode is active. These are modes that you will see in the **Modes** tab. Note: the `USER*` modes are used by camera switchers, PINIO etc. They are not the Waypoint User Actions. See the [Waypoints](#waypoints) section to access those.
148 | Operand Value | Name | Notes |
149 |---------------|-------------------|-------|
150 | 0 | FAILSAFE | `true` when a **Failsafe** state has been triggered. |
151 | 1 | MANUAL | `true` when you are in the **Manual** flight mode. |
152 | 2 | RTH | `true` when you are in the **Return to Home** flight mode. |
153 | 3 | POSHOLD | `true` when you are in the **Position Hold** or **Loiter** flight modes. |
154 | 4 | CRUISE | `true` when you are in the **Cruise** flight mode. |
155 | 5 | ALTHOLD | `true` when you the **Altitude Hold** flight mode modifier is active. |
156 | 6 | ANGLE | `true` when you are in the **Angle** flight mode. |
157 | 7 | HORIZON | `true` when you are in the **Horizon** flight mode. |
158 | 8 | AIR | `true` when you the **Airmode** flight mode modifier is active. |
159 | 9 | USER1 | `true` when the **USER 1** mode is active. |
160 | 10 | USER2 | `true` when the **USER 21** mode is active. |
161 | 11 | COURSE_HOLD | `true` when you are in the **Course Hold** flight mode. |
162 | 12 | USER3 | `true` when the **USER 3** mode is active. |
163 | 13 | USER4 | `true` when the **USER 4** mode is active. |
164 | 14 | ACRO | `true` when you are in the **Acro** flight mode. |
165 | 15 | WAYPOINT_MISSION | `true` when you are in the **WP Mission** flight mode. |
169 | Operand Value | Name | Notes |
170 |---------------|-------------------------------|-------|
171 | 0 | Is WP | Boolean `0`/`1` |
172 | 1 | Current Waypoint Index | Current waypoint leg. Indexed from `1`. To verify WP is in progress, use `Is WP` |
173 | 2 | Current Waypoint Action | `true` when Action active in current leg. See ACTIVE_WAYPOINT_ACTION table |
174 | 3 | Next Waypoint Action | `true` when Action active in next leg. See ACTIVE_WAYPOINT_ACTION table |
175 | 4 | Distance to next Waypoint | Distance to next WP in metres |
176 | 5 | Distance from Waypoint | Distance from the last WP in metres |
177 | 6 | User Action 1 | `true` when User Action 1 is active on this waypoint leg [boolean `0`/`1`] |
178 | 7 | User Action 2 | `true` when User Action 2 is active on this waypoint leg [boolean `0`/`1`] |
179 | 8 | User Action 3 | `true` when User Action 3 is active on this waypoint leg [boolean `0`/`1`] |
180 | 9 | User Action 4 | `true` when User Action 4 is active on this waypoint leg [boolean `0`/`1`] |
181 | 10 | Next Waypoint User Action 1 | `true` when User Action 1 is active on the next waypoint leg [boolean `0`/`1`] |
182 | 11 | Next Waypoint User Action 2 | `true` when User Action 2 is active on the next waypoint leg [boolean `0`/`1`] |
183 | 12 | Next Waypoint User Action 3 | `true` when User Action 3 is active on the next waypoint leg [boolean `0`/`1`] |
184 | 13 | Next Waypoint User Action 4 | `true` when User Action 4 is active on the next waypoint leg [boolean `0`/`1`] |
187 #### ACTIVE_WAYPOINT_ACTION
190 |---------------|-------|
201 All flags are reseted on ARM and DISARM event.
203 | bit | Decimal | Function |
204 |-------|-----------|-----------|
205 | 0 | 1 | Latch - after activation LC will stay active until LATCH flag is reset |
206 | 1 | 2 | Timeout satisfied - Used in timed operands to determine if the timeout has been met |
212 `gvar <index> <default value> <min> <max>`
216 `pid <index> <enabled> <setpoint type> <setpoint value> <measurement type> <measurement value> <P gain> <I gain> <D gain> <FF gain>`
218 * `<index>` - ID of PID Controller, starting from `0`
219 * `<enabled>` - `0` evaluates as disabled, `1` evaluates as enabled
220 * `<setpoint type>` - See `Operands` paragraph
221 * `<setpoint value>` - See `Operands` paragraph
222 * `<measurement type>` - See `Operands` paragraph
223 * `<measurement value>` - See `Operands` paragraph
224 * `<P gain>` - P-gain, scaled to `1/1000`
225 * `<I gain>` - I-gain, scaled to `1/1000`
226 * `<D gain>` - D-gain, scaled to `1/1000`
227 * `<FF gain>` - FF-gain, scaled to `1/1000`
231 ### When more than 100 meters away, increase VTX power
232 ![screenshot of vtx home distance](./assets/images/vtx_home_distance.png)
234 ### When more than 600 meters away, engage return-to-home by setting the matching RC channel
235 ![screenshot of rth home distance](./assets/images/rth_home_distance.jpg)
238 ### Dynamic THROTTLE scale
240 `logic 0 1 0 23 0 50 0 0 0`
242 Limits the THROTTLE output to 50% when Logic Condition `0` evaluates as `true`
244 ### Set VTX power level via Smart Audio
246 `logic 0 1 0 25 0 3 0 0 0`
248 Sets VTX power level to `3` when Logic Condition `0` evaluates as `true`
250 ### Invert ROLL and PITCH when rear facing camera FPV is used
252 Solves the problem from [https://github.com/iNavFlight/inav/issues/4439](https://github.com/iNavFlight/inav/issues/4439)
255 logic 0 1 0 26 0 0 0 0 0
256 logic 1 1 0 27 0 0 0 0 0
259 Inverts ROLL and PITCH input when Logic Condition `0` evaluates as `true`. Moving Pitch stick up will cause pitch down (up for rear facing camera). Moving Roll stick right will cause roll left of a quad (right in rear facing camera)
261 ### Cut motors but keep other throttle bindings active
263 `logic 0 1 0 29 0 1000 0 0 0`
265 Sets throttle output to `0%` when Logic Condition `0` evaluates as `true`
267 ### Set throttle to 50% and keep other throttle bindings active
269 `logic 0 1 0 29 0 1500 0 0 0`
271 Sets throttle output to about `50%` when Logic Condition `0` evaluates as `true`
273 ### Set throttle control to different RC channel
275 `logic 0 1 0 29 1 7 0 0 0`
277 If Logic Condition `0` evaluates as `true`, motor throttle control is bound to RC channel 7 instead of throttle channel
279 ### Set VTX channel with a POT
281 Set VTX channel with a POT on the radio assigned to RC channel 6
284 logic 0 1 -1 15 1 6 0 1000 0
285 logic 1 1 -1 37 4 0 0 7 0
286 logic 2 1 -1 14 4 1 0 1 0
287 logic 3 1 -1 31 4 2 0 0 0
291 1. Normalize range `[1000:2000]` to `[0:1000]` by substracting `1000`
292 2. Scale range `[0:1000]` to `[0:7]`
293 3. Increase range by `1` to have the range of `[1:8]`
294 4. Assign LC#2 to VTX channel function
296 ### Set VTX power with a POT
298 Set VTX power with a POT on the radio assigned to RC channel 6. In this example we scale POT to 4 power level `[1:4]`
301 logic 0 1 -1 15 1 6 0 1000 0
302 logic 1 1 -1 37 4 0 0 3 0
303 logic 2 1 -1 14 4 1 0 1 0
304 logic 3 1 -1 25 4 2 0 0 0
308 1. Normalize range [1000:2000] to [0:1000] by substracting `1000`
309 2. Scale range [0:1000] to [0:3]
310 3. Increase range by `1` to have the range of [1:4]
311 4. Assign LC#2 to VTX power function